home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
djgpp
/
go32
/
fs
/
syms.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-23
|
41KB
|
1,367 lines
/*
** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
**
** This file is distributed under the terms listed in the document
** "copying.dj", available from DJ Delorie at the address above.
** A copy of "copying.dj" should accompany this file; if not, a copy
** should be available from where this file was obtained. This file
** may not be distributed without a verbatim copy of "copying.dj".
**
** This file is distributed WITHOUT ANY WARRANTY; without even the implied
** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
/* Modified by Morten Welinder, terra@diku.dk, for use with full screen
debugger. These changes are copyright 1994 by Morten Welinder. */
/* Modified by Long Doan, ld@netrix.com, to reduce memory usage.
These changes are copyrighted 1994-1995 by Long Doan. */
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <dos.h>
#include <sys/stat.h>
#include "ed.h"
#include "coff.h"
#include "syms.h"
#include "stab.h"
#include "wild.h"
/* END_OF_INCLUDES */
#define DO_SYMS 1
#define SYM_FILE_VERSION 0x00010005
int undefined_symbol=0;
#define Ofs(n) ((int)&(((TSS *)0)->n))
struct {
char *name;
int size;
int ofs;
} regs[] = {
{"%eip" , 4, Ofs(tss_eip) },
{"%eflags", 4, Ofs(tss_eflags)},
{"%eax" , 4, Ofs(tss_eax) },
{"%ebx" , 4, Ofs(tss_ebx) },
{"%ecx" , 4, Ofs(tss_ecx) },
{"%edx" , 4, Ofs(tss_edx) },
{"%esp" , 4, Ofs(tss_esp) },
{"%ebp" , 4, Ofs(tss_ebp) },
{"%esi" , 4, Ofs(tss_esi) },
{"%edi" , 4, Ofs(tss_edi) },
{"%ax" , 2, Ofs(tss_eax) },
{"%bx" , 2, Ofs(tss_ebx) },
{"%cx" , 2, Ofs(tss_ecx) },
{"%dx" , 2, Ofs(tss_edx) },
{"%ah" , 1, Ofs(tss_eax)+1 },
{"%bh" , 1, Ofs(tss_ebx)+1 },
{"%ch" , 1, Ofs(tss_ecx)+1 },
{"%dh" , 1, Ofs(tss_edx)+1 },
{"%al" , 1, Ofs(tss_eax) },
{"%bl" , 1, Ofs(tss_ebx) },
{"%cl" , 1, Ofs(tss_ecx) },
{"%dl" , 1, Ofs(tss_edx) },
{0 , 0, 0 }
};
#if !DO_SYMS
void syms_init(char *fname) {}
void syms_list(int byval) {}
void syms_listwild(char *pattern) {}
word32 syms_name2val(char *name)
{
if (isdigit(name[0]))
{
int v;
if (strncmp(name, "0x", 2) == 0)
sscanf(name+2, "%x", &v);
else
sscanf(name, "%d", &v);
undefined_symbol = 0;
return v;
}
else
{
undefined_symbol = 1;
return 0;
}
}
char *syms_val2name(word32 val, word32 *delta)
{
static char noname_buf[20];
sprintf(noname_buf, "%#lx", val);
*delta = 0;
return noname_buf;
}
char *syms_val2line(word32 val, int *lineret, int exact)
{
return 0;
}
char *get_module(int count);
{
static char noname_buf[20];
sprintf(noname_buf, "%s", "Why call me here?");
return noname_buf;
}
word32 get_linenum(int filenum, int linenum);
{
return 0;
}
#else
/* From the file */
typedef struct SYM_ENTRY {
word32 string_off;
word8 type;
word8 other;
word16 desc;
word32 val;
} SYM_ENTRY;
static FILHDR f_fh;
static AOUTHDR f_ah;
static SCNHDR *f_sh = NULL;
static SYMENT *f_symtab = NULL;
static SYM_ENTRY *f_aoutsyms = NULL;
static AUXENT *f_aux = NULL;
static LINENO **f_lnno = NULL;
static char *f_string_table = NULL;
static char *f_types = NULL;
/* built internally */
typedef struct {
char *filename;
word32 first_address;
word32 last_address;
LINENO *lines;
int num_lines;
} FileNode;
static FileNode *files;
static int num_files;
typedef struct SymNode {
char *name;
word32 address;
char type_c;
} SymNode;
typedef struct SymAddr {
char *name;
word32 address;
char type_c;
word32 range;
} SymAddr;
/* -----------------------------------------------------------------
- Structures used to dump/read symbols to/from a file.
----------------------------------------------------------------- */
typedef struct SymFileHeader {
word32 version;
word32 syms_num;
word32 syms_size;
word32 file_time;
word32 files_num;
word32 start_file;
word32 file_size;
} SymFileHeader;
typedef struct SymFileEntry {
word32 offset;
} SymFileEntry;
typedef struct HiloName {
char *name;
int index;
} HiloName;
typedef struct HiloAddr {
word32 addr;
int index;
} HiloAddr;
/* -----------------------------------------------------------------
- Structures used to dump/read line numbers to/from a file.
----------------------------------------------------------------- */
typedef struct FileFileEntry {
char name[100];
word32 lines_num;
word32 first_addr;
word32 last_addr;
word32 start_line;
} FileFileEntry;
typedef struct LineInfo {
word32 addr;
word32 l_no;
word32 range;
} LineInfo;
typedef struct CacheInfo {
word32 b_addr;
word32 e_addr;
int cached_files;
int *files_cached;
word32 *begin;
word32 *end;
} CacheInfo;
/* -----------------------------------------------------------------
- Original variables used to store symbols.
----------------------------------------------------------------- */
static SymNode *syms;
static int num_syms;
/* -----------------------------------------------------------------
- New variables used to store symbols.
----------------------------------------------------------------- */
#define SYM_CACHE_SIZE 100
#define LINE_CACHE_SIZE 682
#define LINE_CACHE_SKIP 100
#define MAX_HILO_CACHE 33
static FILE *sym_file;
static SymFileHeader sym_header;
static SymNode name_cache[SYM_CACHE_SIZE];
static word32 name_cached[SYM_CACHE_SIZE];
static SymAddr addr_cache[SYM_CACHE_SIZE];
static HiloName *name_hilo_cache;
static HiloAddr *addr_hilo_cache;
static int name_in_cache = 0;
static int addr_in_cache = 0;
static int entry_to_free = 0;
static int cached_name_end = 0;
static int cached_name_free = 0;
static int hilo_cache_size;
static FileFileEntry *file_entries;
static LINENO line_cache[LINE_CACHE_SIZE];
static CacheInfo line_cache_info;
static char dos_buffer[4096];
/* -----------------------------------------------------------------
- Utilities
----------------------------------------------------------------- */
static int syms_sort_bn(const void *a, const void *b)
{ SymNode *sa = (SymNode *)a;
SymNode *sb = (SymNode *)b;
return strcmp(sa->name, sb->name);
}
/* ----------------------------------------------------------------- */
static int syms_sort_bv(const void *a, const void *b)
{ SymAddr *sa = (SymAddr *)a;
SymAddr *sb = (SymAddr *)b;
return sa->address - sb->address;
}
/* ----------------------------------------------------------------- */
static char *symndup(char *s, int len)
{ char c = s[len], *rv;
s[len] = 0;
rv = strdup(s);
s[len] = c;
return rv;
}
/* ----------------------------------------------------------------- */
static void
get_sym_name_by_num (SymNode *sym, word32 num)
{ word32 offset;
int i;
SymFileEntry entry;
if (num >= num_syms)
return;
for (i = 0; i < cached_name_end; i++)
if (name_cached[i] == num)
{ sym->address = name_cache[i].address;
sym->type_c = name_cache[i].type_c;
strcpy (sym->name, name_cache[i].name);
return;
}
offset = num * sizeof (SymFileEntry) + sym_header.syms_size;
fseek (sym_file, offset, SEEK_SET);
fread (&entry, sizeof (SymFileEntry) , 1, sym_file);
fseek (sym_file, entry.offset, SEEK_SET);
fread (&(sym->address) , sizeof (word32), 1, sym_file);
fread (&(sym->type_c) , sizeof (char) , 1, sym_file);
fgets (sym->name, 150, sym_file);
sym->name[strlen (sym->name) - 1] = 0;
if (cached_name_end == SYM_CACHE_SIZE)
{ i = cached_name_free;
cached_name_free++;
if (cached_name_free == cached_name_end)
cached_name_free = 0;
} else
{ i = cached_name_end;
cached_name_end++;
name_cache[i].name = malloc (151);
}
name_cache[i].address = sym->address;
name_cache[i].type_c = sym->type_c;
strcpy (name_cache[i].name, sym->name);
name_cached[i] = num;
}
/* ----------------------------------------------------------------- */
static void
get_sym_addr_by_num (SymNode *sym, word32 num)
{ word32 offset;
SymFileEntry entry;
if (num >= num_syms)
return;
offset = (num + num_syms) * sizeof (SymFileEntry) + sym_header.syms_size;
fseek (sym_file, offset, SEEK_SET);
fread (&entry, sizeof (SymFileEntry) , 1, sym_file);
fseek (sym_file, entry.offset, SEEK_SET);
fread (&(sym->address) , sizeof (word32) , 1, sym_file);
fread (&(sym->type_c) , sizeof (char) , 1, sym_file);
fgets (sym->name, 150, sym_file);
sym->name[strlen (sym->name) - 1] = 0;
}
/* ----------------------------------------------------------------- */
static void
init_cache (void)
{ int hi, lo, count, c_hi, c_lo, interval;
char temp[151];
SymNode sym;
for (hilo_cache_size = MAX_HILO_CACHE; hilo_cache_size > num_syms;
hilo_cache_size--)
;
if (!(hilo_cache_size % 2))
hilo_cache_size--;
if (hilo_cache_size == 1)
hilo_cache_size = 0;
if (hilo_cache_size <= 0)
{ hilo_cache_size = 0;
return;
}
name_hilo_cache = malloc (hilo_cache_size * sizeof (HiloName));
addr_hilo_cache = malloc (hilo_cache_size * sizeof (HiloAddr));
count = hilo_cache_size;
hi = num_syms - 1;
lo = 0;
interval = num_syms / (hilo_cache_size - 1);
c_hi = hilo_cache_size - 1;
c_lo = 0;
sym.name = temp;
while (count > 1)
{ get_sym_name_by_num (&sym, lo);
name_hilo_cache[c_lo].name = strdup (sym.name);
name_hilo_cache[c_lo].index = lo;
get_sym_name_by_num (&sym, hi);
name_hilo_cache[c_hi].name = strdup (sym.name);
name_hilo_cache[c_hi].index = hi;
get_sym_addr_by_num (&sym, lo);
addr_hilo_cache[c_lo].addr = sym.address;
addr_hilo_cache[c_lo].index = lo;
get_sym_addr_by_num (&sym, hi);
addr_hilo_cache[c_hi].addr = sym.address;
addr_hilo_cache[c_hi].index = hi;
count -= 2;
hi -= interval;
lo += interval;
if (lo > hi)
lo = hi;
c_hi--;
c_lo++;
}
get_sym_name_by_num (&sym, lo);
name_hilo_cache[c_lo].name = strdup (sym.name);
name_hilo_cache[c_lo].index = lo;
sym.name = temp;
get_sym_addr_by_num (&sym, lo);
addr_hilo_cache[c_lo].addr = sym.address;
addr_hilo_cache[c_lo].index = lo;
line_cache_info.cached_files = 0;
line_cache_info.files_cached = malloc (sizeof (int));
line_cache_info.begin = malloc (sizeof (word32));
line_cache_info.end = malloc (sizeof (word32));
}
/* ----------------------------------------------------------------- */
static void
get_name_hilo (char *name, int *hi, int *lo)
{ int c_hi, c_lo;
if (!hilo_cache_size)
{ *hi = -1;
*lo = -1;
return;
}
c_hi = hilo_cache_size - 1;
c_lo = 0;
while ((c_hi >= 0) && (strcmp (name, name_hilo_cache[c_hi].name) <= 0))
c_hi--;
if (c_hi < hilo_cache_size - 1)
c_hi++;
while ((c_lo <= c_hi) && (strcmp (name, name_hilo_cache[c_lo].name) >= 0))
c_lo++;
if (c_lo > 0)
c_lo--;
*hi = name_hilo_cache[c_hi].index;
*lo = name_hilo_cache[c_lo].index;
}
/* ----------------------------------------------------------------- */
static void
get_addr_hilo (word32 addr, int *hi, int *lo)
{ int c_hi, c_lo;
if (!hilo_cache_size)
{ *hi = -1;
*lo = -1;
return;
}
c_hi = hilo_cache_size - 1;
c_lo = 0;
if (addr > addr_hilo_cache[c_hi].addr ||
addr < addr_hilo_cache[c_lo].addr)
{ *hi = -1;
*lo = -1;
return;
}
while ((c_hi >= 0) && (addr <= addr_hilo_cache[c_hi].addr))
c_hi--;
if (c_hi < hilo_cache_size - 1)
c_hi++;
while ((c_lo <= c_hi) && (addr >= addr_hilo_cache[c_lo].addr))
c_lo++;
if (c_lo > 0)
c_lo--;
*hi = addr_hilo_cache[c_hi].index;
*lo = addr_hilo_cache[c_lo].index;
}
/* ----------------------------------------------------------------- */
static int valid_symbol(int i)
{ char *sn;
if (f_symtab[i].e.e.e_zeroes)
sn = f_symtab[i].e.e_name;
else
sn = f_string_table + f_symtab[i].e.e.e_offset;
if (sn[0] != '_')
return 0;
if (strncmp(sn, "___gnu_compiled", 15) == 0)
return 0;
if (strcmp(sn, "__DYNAMIC") == 0)
return 0;
return 1;
}
/* ----------------------------------------------------------------- */
static void process_coff(FILE *fd, long ofs)
{ int i, f, s, f_pending;
LINENO *l = 0;
int l_pending;
word32 strsize;
char *name;
fseek(fd, ofs, 0);
fread(&f_fh, 1, FILHSZ, fd);
fread(&f_ah, 1, AOUTSZ, fd);
f_sh = (SCNHDR *)malloc(f_fh.f_nscns * SCNHSZ);
f_types = (char *)malloc(f_fh.f_nscns);
f_lnno = (LINENO **)malloc(f_fh.f_nscns * sizeof(LINENO *));
fread(f_sh, f_fh.f_nscns, SCNHSZ, fd);
for (i=0; i<f_fh.f_nscns; i++)
{ if (f_sh[i].s_flags & STYP_TEXT)
f_types[i] = 'T';
if (f_sh[i].s_flags & STYP_DATA)
f_types[i] = 'D';
if (f_sh[i].s_flags & STYP_BSS)
f_types[i] = 'B';
if (f_sh[i].s_nlnno)
{ fseek(fd, ofs + f_sh[i].s_lnnoptr, 0L);
f_lnno[i] = (LINENO *)malloc(f_sh[i].s_nlnno * LINESZ);
fread(f_lnno[i], LINESZ, f_sh[i].s_nlnno, fd);
} else
f_lnno[i] = 0;
}
fseek(fd, ofs + f_fh.f_symptr + f_fh.f_nsyms * SYMESZ, 0);
fread(&strsize, 1, 4, fd);
f_string_table = (char *)malloc(strsize);
fread(f_string_table+4, 1, strsize-4, fd);
f_string_table[0] = 0;
fseek(fd, ofs+f_fh.f_symptr, 0);
f_symtab = (SYMENT *)malloc(f_fh.f_nsyms * SYMESZ);
fread(f_symtab, SYMESZ, f_fh.f_nsyms, fd);
f_aux = (AUXENT *)f_symtab;
num_syms = num_files = 0;
for (i=0; i<f_fh.f_nsyms; i++)
{ switch (f_symtab[i].e_sclass)
{ case C_FILE:
num_files++;
break;
case C_EXT:
case C_STAT:
if (!valid_symbol(i))
break;
num_syms++;
break;
}
i += f_symtab[i].e_numaux;
}
files = (FileNode *)malloc(num_files * sizeof(FileNode));
syms = (SymNode *)malloc(num_syms * sizeof(SymNode));
f = s = f_pending = l_pending = 0;
for (i=0; i<f_fh.f_nsyms; i++)
{ switch (f_symtab[i].e_sclass)
{ case C_FILE:
if (f_aux[i+1].x_file.x_n.x_zeroes)
/* -----------------------------------------------------------------
- This will return in a lost of 16 bytes in memory when the name is freed.
----------------------------------------------------------------- */
files[f].filename = symndup(f_aux[i+1].x_file.x_fname, 16);
else
files[f].filename = f_string_table + f_aux[i+1].x_file.x_n.x_offset;
files[f].lines = 0;
f_pending = 1;
f++;
break;
case C_EXT:
case C_STAT:
if (f_symtab[i].e.e.e_zeroes)
name = f_symtab[i].e.e_name;
else
name = f_string_table + f_symtab[i].e.e.e_offset;
if (f_pending && strcmp(name, ".text") == 0)
{ files[f-1].first_address = f_symtab[i].e_value;
files[f-1].last_address = f_symtab[i].e_value + f_aux[i+1].x_scn.x_scnlen - 1;
files[f-1].num_lines = f_aux[i+1].x_scn.x_nlinno;
f_pending = 0;
}
if (ISFCN(f_symtab[i].e_type))
{ int scn = f_symtab[i].e_scnum - 1;
l = f_lnno[scn] + ((f_aux[i+1].x_sym.x_fcnary.x_fcn.x_lnnoptr - f_sh[scn].s_lnnoptr)/LINESZ);
l_pending = 1;
l->l_addr.l_paddr = f_symtab[i].e_value;
}
if (!valid_symbol(i))
break;
syms[s].address = f_symtab[i].e_value;
if (f_symtab[i].e.e.e_zeroes)
/* -----------------------------------------------------------------
- This will return in a lost of 8 bytes in memory when the name is freed.
----------------------------------------------------------------- */
syms[s].name = symndup(f_symtab[i].e.e_name, 8);
else
syms[s].name = f_string_table + f_symtab[i].e.e.e_offset;
switch (f_symtab[i].e_scnum)
{ case 1 ... 10:
syms[s].type_c = f_types[f_symtab[i].e_scnum-1];
break;
case N_UNDEF:
syms[s].type_c = 'U';
break;
case N_ABS:
syms[s].type_c = 'A';
break;
case N_DEBUG:
syms[s].type_c = 'D';
break;
}
if (f_symtab[i].e_sclass == C_STAT)
syms[s].type_c += 'a' - 'A';
s++;
break;
case C_FCN:
if (f_pending && files[f-1].lines == 0)
{ files[f-1].lines = l;
}
if (l_pending)
{ int lbase = f_aux[i+1].x_sym.x_misc.x_lnsz.x_lnno - 1;
int i2;
l->l_lnno = lbase;
l++;
for (i2=0; l[i2].l_lnno; i2++)
l[i2].l_lnno += lbase;
l_pending = 0;
}
break;
}
i += f_symtab[i].e_numaux;
}
}
/* ----------------------------------------------------------------- */
static void process_aout(FILE *fd, long ofs)
{ GNU_AOUT header;
word32 string_table_length;
int nsyms, i, f, s, l;
fseek(fd, ofs, 0);
fread(&header, 1, sizeof(header), fd);
fseek(fd, ofs + sizeof(header) + header.tsize + header.dsize + header.txrel + header.dtrel, 0);
nsyms = header.symsize / sizeof(SYM_ENTRY);
f_aoutsyms = (SYM_ENTRY *)malloc(header.symsize);
fread(f_aoutsyms, 1, header.symsize, fd);
fread(&string_table_length, 1, 4, fd);
f_string_table = (char *)malloc(string_table_length);
fread(f_string_table+4, 1, string_table_length-4, fd);
f_string_table[0] = 0;
num_files = num_syms = 0;
for (i=0; i<nsyms; i++)
{ char *symn = f_string_table + f_aoutsyms[i].string_off;
char *cp;
switch (f_aoutsyms[i].type & ~N_EXT)
{ case N_SO:
if (symn[strlen(symn)-1] == '/')
break;
num_files++;
break;
case N_TEXT:
cp = symn + strlen(symn) - 2;
if (strncmp(symn, "___gnu", 6) == 0 ||
strcmp(cp, "d.") == 0 /* as in gcc_compiled. */ ||
strcmp(cp, ".o") == 0)
break;
case N_DATA:
case N_ABS:
case N_BSS:
case N_FN:
case N_SETV:
case N_SETA:
case N_SETT:
case N_SETD:
case N_SETB:
case N_INDR:
num_syms ++;
break;
}
}
syms = (SymNode *)malloc(num_syms * sizeof(SymNode));
memset(syms, num_syms * sizeof(SymNode), 0);
files = (FileNode *)malloc(num_files * sizeof(FileNode));
memset(files, num_files * sizeof(FileNode), 0);
f = s = 0;
for (i=0; i<nsyms; i++)
{ char c, *cp;
char *symn = f_string_table + f_aoutsyms[i].string_off;
switch (f_aoutsyms[i].type & ~N_EXT)
{ case N_SO:
if (symn[strlen(symn)-1] == '/')
break;
if (f && files[f-1].last_address == 0)
files[f-1].last_address = f_aoutsyms[i].val - 1;
files[f].filename = symn;
files[f].first_address = f_aoutsyms[i].val;
f ++;
break;
case N_SLINE:
files[f-1].num_lines++;
break;
case N_TEXT:
cp = symn + strlen(symn) - 2;
if (strncmp(symn, "___gnu", 6) == 0 ||
strcmp(cp, "d.") == 0 /* as in gcc_compiled. */ ||
strcmp(cp, ".o") == 0)
{ if (f && files[f-1].last_address == 0)
files[f-1].last_address = f_aoutsyms[i].val - 1;
break;
}
c = 't';
goto sym_c;
case N_DATA:
c = 'd';
goto sym_c;
case N_ABS:
c = 'a';
goto sym_c;
case N_BSS:
c = 'b';
goto sym_c;
case N_FN:
c = 'f';
goto sym_c;
case N_SETV:
c = 'v';
goto sym_c;
case N_SETA:
c = 'v';
goto sym_c;
case N_SETT:
c = 'v';
goto sym_c;
case N_SETD:
c = 'v';
goto sym_c;
case N_SETB:
c = 'v';
goto sym_c;
case N_INDR:
c = 'i';
sym_c:
syms[s].name = symn;
syms[s].address = f_aoutsyms[i].val;
syms[s].type_c = (f_aoutsyms[i].type & N_EXT) ? (c+'A'-'a') : c;
s ++;
break;
}
}
l = f = 0;
for (i=0; i<nsyms; i++)
{ char *symn = f_string_table + f_aoutsyms[i].string_off;
switch (f_aoutsyms[i].type & ~N_EXT)
{ case N_SO:
if (symn[strlen(symn)-1] == '/')
break;
files[f].lines = (LINENO *)malloc(files[f].num_lines * sizeof(LINENO));
f++;
l = 0;
break;
case N_SLINE:
files[f-1].lines[l].l_addr.l_paddr = f_aoutsyms[i].val;
files[f-1].lines[l].l_lnno = f_aoutsyms[i].desc;
l ++;
break;
}
}
}
/* ----------------------------------------------------------------- */
static void process_file(FILE *fd, long ofs)
{ short s, exe[2];
fseek(fd, ofs, 0);
fread(&s, 1, 2, fd);
switch (s)
{ case 0x5a4d: /* .exe */
fread(exe, 2, 2, fd);
ofs += (long)exe[1] * 512L;
if (exe[0])
ofs += (long)exe[0] - 512L;
process_file(fd, ofs);
break;
case 0x014c: /* .coff */
process_coff(fd, ofs);
break;
case 0x010b: /* a.out ZMAGIC */
case 0x0107: /* a.out object */
process_aout(fd, ofs);
break;
}
}
/* -----------------------------------------------------------------
- Interface fuctions.
----------------------------------------------------------------- */
void syms_init(char *fname)
{ FILE *fd = fopen(fname, "rb");
int i, len = strlen (fname);
word32 org_time;
char *symfilename = alloca (len + 4);
/* struct stat statbuf; */
int used = 0, left = 4096;
if (fd == 0)
{ perror(fname);
} else
{ SymFileEntry *name_entries, *addr_entries;
word32 sym_offset;
SymAddr *syms_byaddr;
getftime (fileno (fd), (struct ftime *)&org_time);
strcpy (symfilename, sympath);
strcpy (symfilename + strlen (symfilename), symname);
symfilename[strlen (symfilename) + 1] = 0;
symfilename[strlen (symfilename)] = '.';
strcpy (symfilename + strlen (symfilename), symext);
/* if (stat(symfilename, &statbuf) != -1) */
/* if (0 == access (symfilename, 4)) */
sym_file = fopen (symfilename, "rb");
/* else
sym_file = 0; */
if (sym_file)
{ fread (&sym_header, sizeof (SymFileHeader), 1, sym_file);
if (sym_header.file_time == org_time &&
sym_header.version == SYM_FILE_VERSION)
{ num_syms = sym_header.syms_num;
num_files = sym_header.files_num;
fseek (sym_file, 0, SEEK_END);
sym_offset = ftell (sym_file);
if (sym_offset == sym_header.file_size)
{ printf ("Use symbol file %s\n", symfilename);
init_cache ();
fseek (sym_file, sym_header.start_file, SEEK_SET);
file_entries = malloc (num_files * sizeof (FileFileEntry));
fread (file_entries, sizeof (FileFileEntry), num_files, sym_file);
return;
}
}
fclose (sym_file);
}
printf ("Create symbol file %s\n", symfilename);
sym_file = fopen (symfilename, "wb");
process_file(fd, 0);
fclose(fd);
sym_header.version = SYM_FILE_VERSION;
sym_header.syms_num = num_syms;
sym_header.file_time = org_time;
sym_header.files_num = num_files;
fwrite (&sym_header, sizeof (SymFileHeader), 1, sym_file);
name_entries = (SymFileEntry *)malloc (num_syms * sizeof (SymFileEntry));
addr_entries = (SymFileEntry *)malloc (num_syms * sizeof (SymFileEntry));
/* -----------------------------------------------------------------
- Sort the original symbol table by name, and move to file.
----------------------------------------------------------------- */
sym_offset = sizeof (SymFileHeader);
qsort(syms, num_syms, sizeof(SymNode), syms_sort_bn);
for (i = 0; i < num_syms; i++)
{ name_entries[i].offset = sym_offset;
len = strlen (syms[i].name) + 1;
if (left < 5 + len)
{ fwrite (dos_buffer, 1, used, sym_file);
used = 0;
left = 4096;
}
*(word32 *)(dos_buffer + used) = syms[i].address;
*(dos_buffer + used + 4) = syms[i].type_c;
strcpy (dos_buffer + used + 5, syms[i].name);
*(dos_buffer + used + len + 4) = '\n';
used += len + 5;
left -= len + 5;
sym_offset += len + 5;
/* free (syms[i].name); */
}
if (used)
fwrite (dos_buffer, 1, used, sym_file);
sym_header.syms_size = sym_offset;
/* -----------------------------------------------------------------
- Sort the original symbol table by address, and record their offset.
----------------------------------------------------------------- */
syms_byaddr = (SymAddr *)malloc(num_syms * sizeof(SymAddr));
for (i = 0; i < num_syms; i++)
{ memcpy(&(syms_byaddr[i]), &(syms[i]), sizeof(SymNode));
syms_byaddr[i].range = i;
}
qsort(syms_byaddr, num_syms, sizeof(SymAddr), syms_sort_bv);
for (i = 0; i < num_syms; i++)
addr_entries[i].offset = name_entries[syms_byaddr[i].range].offset;
free (syms);
free (syms_byaddr);
/* -----------------------------------------------------------------
- Write the offset tables to the file and free them.
----------------------------------------------------------------- */
fwrite (name_entries, sizeof (SymFileEntry), num_syms, sym_file);
fwrite (addr_entries, sizeof (SymFileEntry), num_syms, sym_file);
free (name_entries);
free (addr_entries);
sym_header.start_file = sym_header.syms_size +
2 * num_syms * sizeof (SymFileEntry);
sym_header.file_size = sym_header.start_file +
num_files * sizeof (FileFileEntry);
/* -----------------------------------------------------------------
- Write the line number information to the file, and free them.
----------------------------------------------------------------- */
file_entries = malloc (num_files * sizeof (FileFileEntry));
for (i = 0; i < num_files; i++)
{ file_entries[i].lines_num = files[i].num_lines;
file_entries[i].start_line = sym_header.file_size;
file_entries[i].first_addr = files[i].first_address;
file_entries[i].last_addr = files[i].last_address;
strncpy (file_entries[i].name, files[i].filename, 99);
sym_header.file_size += files[i].num_lines * LINESZ;
}
fwrite (file_entries, sizeof (FileFileEntry), num_files, sym_file);
for (i = 0; i < num_files; i++)
{ fwrite (files[i].lines, LINESZ, files[i].num_lines, sym_file);
free (files[i].lines);
/* free (files[i].filename); */
}
free (files);
free (f_string_table);
free (f_sh);
free (f_symtab);
free (f_aoutsyms);
free (f_aux);
free (f_lnno);
free (f_types);
/* -----------------------------------------------------------------
- Write the adjusted header to the file.
----------------------------------------------------------------- */
fseek (sym_file, 0, SEEK_SET);
fwrite (&sym_header, sizeof (SymFileHeader), 1, sym_file);
fclose (sym_file);
/* -----------------------------------------------------------------
- Test the intergity of the file.
----------------------------------------------------------------- */
sym_file = fopen (symfilename, "rb");
fseek (sym_file, 0, SEEK_END);
sym_offset = ftell (sym_file);
if (sym_offset != sym_header.file_size)
{ fclose (sym_file);
perror (symfilename);
}
}
init_cache ();
}
/* ----------------------------------------------------------------- */
static void
get_sym_by_name (SymNode *sym, char *name)
{ int hi, lo, mid, found = 0;
int err;
get_name_hilo (name, &hi, &lo);
if (hi < 0 || lo < 0)
{ sym->name = 0;
return;
}
sym->name = malloc (151);
do
{ mid = (hi + lo) / 2;
get_sym_name_by_num (sym, mid);
err = strcmp (name, sym->name);
if (err == 0)
found = 1;
else if (err < 0)
hi = mid;
else
lo = mid;
err = (hi - lo <= 1) && !found;
} while (!found && !err);
if (err)
{ free (sym->name);
sym->name = 0;
}
}
/* ----------------------------------------------------------------- */
static int
get_sym_by_addr (word32 addr)
{ int hi, lo, mid;
word32 offset, start_offset;
SymFileEntry entry;
SymNode sym_n;
if (addr < 0x1000)
return (-1);
for (mid = 0; mid < addr_in_cache; mid++)
if (addr_cache[mid].address <= addr && addr <= addr_cache[mid].range)
return (mid);
get_addr_hilo (addr, &hi, &lo);
if (hi < 0 || lo < 0)
return (-1);
sym_n.name = malloc (151);
start_offset = sym_header.syms_size + num_syms * sizeof (SymFileEntry);
do
{ mid = (hi + lo) / 2;
get_sym_addr_by_num (&sym_n, mid);
if (sym_n.address == addr)
break;
if (sym_n.address > addr)
hi = mid;
else
lo = mid;
} while (hi - lo > 1);
if (sym_n.address > addr)
mid--; /* the last below was it */
if (mid >= 0)
{ get_sym_addr_by_num (&sym_n, mid);
offset = (mid + 1) * sizeof (SymFileEntry) + start_offset;
fseek (sym_file, offset, SEEK_SET);
fread (&entry, sizeof (SymFileEntry) , 1, sym_file);
fseek (sym_file, entry.offset, SEEK_SET);
fread (&start_offset, sizeof (word32), 1, sym_file);
} else
{ free (sym_n.name);
return (-1);
}
if (addr_in_cache == SYM_CACHE_SIZE)
{ free (addr_cache[entry_to_free].name);
mid = entry_to_free;
entry_to_free++;
if (entry_to_free == addr_in_cache)
entry_to_free = 0;
} else
{ mid = addr_in_cache;
addr_in_cache++;
}
addr_cache[mid].name = sym_n.name;
addr_cache[mid].address = sym_n.address;
addr_cache[mid].type_c = sym_n.type_c;
addr_cache[mid].range = start_offset - 1;
return (mid);
}
/* ----------------------------------------------------------------- */
static int
lookup_sym_byname(char *name, int idx, int ofs)
{ SymNode sym;
char temp[151];
sprintf (temp, "%s%s", ofs ? "_" : "", name);
temp[idx + ofs + 1] = '\0';
get_sym_by_name (&sym, temp);
if (!(sym.name))
return (-1);
if (name_in_cache)
free (name_cache[0].name);
else
name_in_cache = 1;
name_cache[0].name = strdup (sym.name);
name_cache[0].address = sym.address;
name_cache[0].type_c = sym.type_c;
free (sym.name);
return (0);
}
/* ----------------------------------------------------------------- */
static void
get_line_block (int file, int line, LINENO *l_info)
{ fseek (sym_file, file_entries[file].start_line + line * LINESZ, SEEK_SET);
fread (l_info, LINESZ, LINE_CACHE_SIZE, sym_file);
}
/* ----------------------------------------------------------------- */
static void
do_fill (word32 addr, int file)
{ int start_line = 0, end_line = 0, count;
int start_file = file, end_file = file, total_lines;
do {
start_line = end_line;
get_line_block (file, start_line, line_cache);
end_line = start_line + LINE_CACHE_SIZE;
if (end_line > file_entries[file].lines_num)
end_line = file_entries[file].lines_num;
for (count = start_line; count < end_line; count++)
{ if (line_cache[count - start_line].l_addr.l_paddr >= addr)
{ start_line = count - LINE_CACHE_SKIP;
total_lines = file_entries[file].lines_num;
while (start_line < 0 && start_file > 0)
{ total_lines += file_entries[--start_file].lines_num;
start_line += file_entries[start_file].lines_num;
}
if (start_line < 0)
start_line = 0;
get_line_block (start_file, start_line, line_cache);
while (total_lines < LINE_CACHE_SIZE && ++end_file < num_files)
total_lines += file_entries[end_file].lines_num;
if (end_file == num_files)
end_file--;
if (total_lines < LINE_CACHE_SIZE)
line_cache_info.e_addr =
line_cache[total_lines - 1].l_addr.l_paddr;
else
line_cache_info.e_addr =
line_cache[LINE_CACHE_SIZE - 1].l_addr.l_paddr;
line_cache_info.cached_files = 0;
while (start_file <= end_file)
{ line_cache_info.cached_files++;
line_cache_info.files_cached =
realloc (line_cache_info.files_cached,
line_cache_info.cached_files * sizeof (int));
line_cache_info.files_cached[line_cache_info.cached_files - 1] =
start_file;
line_cache_info.begin =
realloc (line_cache_info.begin,
line_cache_info.cached_files * sizeof (word32));
line_cache_info.begin[line_cache_info.cached_files - 1] =
file_entries[start_file].first_addr;
line_cache_info.end =
realloc (line_cache_info.end,
line_cache_info.cached_files * sizeof (word32));
line_cache_info.end[line_cache_info.cached_files - 1] =
file_entries[start_file].last_addr;
start_file++;
}
line_cache_info.b_addr = line_cache[0].l_addr.l_paddr;
return;
}
}
} while (end_line < file_entries[file].lines_num);
}
/* ----------------------------------------------------------------- */
static void
fill_line_cache (word32 addr)
{ int f;
for (f = 0; f < num_files; f++)
{ if (addr >= file_entries[f].first_addr &&
addr <= file_entries[f].last_addr &&
file_entries[f].lines_num)
{ do_fill (addr, f);
return;
}
}
}
/* ----------------------------------------------------------------- */
static void
lookup_file_num (word32 addr, int *file)
{ int i;
for (i = 0; i < line_cache_info.cached_files; i++)
{ if (line_cache_info.begin[i] <= addr && addr <= line_cache_info.end[i])
{ *file = line_cache_info.files_cached[i];
return;
}
}
*file = -1;
return;
}
/* ----------------------------------------------------------------- */
static int
lookup_line_cache (word32 addr, int exact, int *file)
{ int i;
if (!line_cache_info.cached_files)
fill_line_cache (addr);
if (addr < line_cache_info.b_addr || addr > line_cache_info.e_addr)
return (-1);
for (i = 0; i < LINE_CACHE_SIZE; i++)
{ if (line_cache[i].l_addr.l_paddr == addr)
{ lookup_file_num (addr, file);
return (line_cache[i].l_lnno);
}
if (line_cache[i].l_addr.l_paddr > addr)
{ if (exact)
return (-1);
else
{ lookup_file_num (addr, file);
return (line_cache[i].l_lnno);
}
}
}
return (-1);
}
/* ----------------------------------------------------------------- */
static word32
get_line_by_num (int file, int num, int exact)
{ int start_line, end_line = 0, count;
LINENO *l_no;
l_no = (LINENO *)dos_buffer;
do {
start_line = end_line; /* Overlap last entry */
get_line_block (file, start_line, l_no);
end_line = start_line + (4096 / LINESZ);
if (end_line >= file_entries[file].lines_num)
end_line = file_entries[file].lines_num - 1;
for (count = start_line; count <= end_line; count++)
{ if (l_no[count - start_line].l_lnno == num)
return (l_no[count - start_line].l_addr.l_paddr);
if (l_no[count - start_line].l_lnno > num)
{ if (exact)
return (0xffffffff);
else if (count > start_line)
return (l_no[count - 1 - start_line].l_addr.l_paddr);
else return (l_no[0].l_addr.l_paddr);
}
}
} while (end_line < file_entries[file].lines_num - 1);
if (exact)
return (0xffffffff);
return (l_no[end_line - start_line].l_addr.l_paddr);
}
/* ----------------------------------------------------------------- */
word32 syms_name2val(char *name)
{ int idx, sign=1, i;
word32 v = 0;
char *cp;
undefined_symbol = 0;
idx = 0;
sscanf(name, "%s", name);
if (name[0] == 0)
return 0;
if (name[0] == '-')
{ sign = -1;
name++;
} else if (name[0] == '+')
name++;
if (isdigit(name[0]))
{ if (sign == -1)
return -strtoul(name, 0, 0);
return strtoul(name, 0, 0);
}
cp = strpbrk(name, "+-");
if (cp)
idx = cp-name;
else
idx = strlen(name);
if (name[0] == '%') /* register */
{ for (i=0; regs[i].name; i++)
if (strncmp(name, regs[i].name, idx) == 0)
{ switch (regs[i].size)
{ case 1:
v = *(word8 *)((word8 *)(&a_tss) + regs[i].ofs);
break;
case 2:
v = *(word16 *)((word8 *)(&a_tss) + regs[i].ofs);
break;
case 4:
v = *(word32 *)((word8 *)(&a_tss) + regs[i].ofs);
break;
}
return v + syms_name2val(name+idx);
}
}
for (i=0; i<idx; i++)
if (name[i] == '#')
{ int f, lnum;
word32 l_addr;
sscanf(name+i+1, "%d", &lnum);
for (f=0; f<num_files; f++)
{ if ((strncmp(name, file_entries[f].name, i) == 0) &&
(file_entries[f].name[i] == 0))
{ l_addr = get_line_by_num (f, lnum, 1);
if (l_addr != 0xffffffff)
return l_addr + syms_name2val(name+idx);
undefined_symbol = 1;
return 0;
}
}
undefined_symbol = 1;
return 0;
}
i = lookup_sym_byname(name, idx, 0);
if (i == -1)
i = lookup_sym_byname(name, idx, 1);
if (i != -1)
return name_cache[i].address * sign + syms_name2val(name+idx);
undefined_symbol = 1;
return 0;
}
/* ----------------------------------------------------------------- */
static char noname_buf[11];
/* ----------------------------------------------------------------- */
char *syms_val2name(word32 val, word32 *delta)
{ int pos;
if (delta)
*delta = 0;
if (num_syms <= 0)
goto noname;
pos = get_sym_by_addr (val);
if (pos < 0)
goto noname;
if (delta)
*delta = val - addr_cache[pos].address;
return (addr_cache[pos].name);
noname:
sprintf(noname_buf, "%#lx", val);
return noname_buf;
}
/* ----------------------------------------------------------------- */
char *syms_val2line(word32 val, int *lineret, int exact)
{ int f;
if (val < line_cache_info.b_addr || val > line_cache_info.e_addr)
fill_line_cache (val);
*lineret = lookup_line_cache (val, exact, &f);
if (*lineret == -1)
return 0;
return (file_entries[f].name);
}
/* ----------------------------------------------------------------- */
static void
get_lots_sym_name_by_num (SymNode *sym, word32 num)
{ static word32 i = 0;
static int used = 0, left = 4096;
word32 offset, j, k;
SymFileEntry entry;
if (num >= num_syms)
return;
if ((i == 0) || (num == 0) || (num != i + 1) || (left < 300))
{ offset = num * sizeof (SymFileEntry) + sym_header.syms_size;
fseek (sym_file, offset, SEEK_SET);
fread (&entry, sizeof (SymFileEntry) , 1, sym_file);
offset = entry.offset;
fseek (sym_file, offset, SEEK_SET);
fread (dos_buffer , 1 , 4096, sym_file);
used = 0;
left = 4096;
}
i = num;
sym->address = *(word32 *)(dos_buffer + used);
sym->type_c = dos_buffer[used + 4];
for (j = used + 5, k = 0; dos_buffer[j] != '\n'; j++, k++)
sym->name[k] = dos_buffer[j];
sym->name[k++] = 0;
j++;
used = j;
left = 4096 - used;
}
/* ----------------------------------------------------------------- */
static char wild_buf[200];
char *
syms_makewild(word32 sym_num)
{ int lnum;
char *name;
SymNode sym;
sym.name = alloca (151);
get_sym_name_by_num (&sym, sym_num);
name = syms_val2line(sym.address, &lnum, 0);
sprintf (wild_buf, "0x%08lx %c %s", sym.address, sym.type_c, sym.name);
if (name)
sprintf (wild_buf + strlen (wild_buf),
", line %d of %s", lnum, name);
return (wild_buf);
}
/* ----------------------------------------------------------------- */
void
syms_get (word32 sym_num, word32 *address, char *type_c)
{ SymNode sym;
sym.name = alloca (151);
get_sym_name_by_num (&sym, sym_num);
*address = sym.address;
*type_c = sym.type_c;
}
/* ----------------------------------------------------------------- */
void syms_listwild(char *pattern,
void (*handler)(word32))
{ int i;
SymNode sym;
sym.name = alloca (151);
for (i=0; i<num_syms; i++)
{ get_lots_sym_name_by_num (&sym, i);
if (wild(pattern, sym.name))
handler (i);
}
}
/* ----------------------------------------------------------------- */
char *get_module(int count)
{ char *s;
if ((count < 0) || (count == num_files))
{ undefined_symbol = 1;
return 0;
}
s = strdup(file_entries[count].name);
return s;
}
/* ----------------------------------------------------------------- */
word32 get_linenum(int filenum, int linenum)
{ if ((filenum < 0) || (filenum >= num_files))
{ undefined_symbol = 1;
return 0;
}
return (get_line_by_num (filenum, linenum, 0));
}
#endif